/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Description: Hmfs-tools resize operator
 */

#include "resize_operator.h"

#include <cinttypes>
#include <cstdlib>
#include <string>
#include <sys/types.h>
#include <unistd.h>

#include "constant.h"
#include "device_manager.h"
#include "hmfs_common.h"
#include "hmfs_io.h"
#include "hmfs_utils.h"
#include "node.h"
#include "resize_defrag.h"
#include "resize_load.h"
#include "securec.h"

namespace OHOS {
namespace Hmfs {
constexpr uint32_t SEGMENT_RESERVED_OFFSET = 2;
constexpr uint32_t CP_PACK_BASE_BLOCK_COUNT = 8;
constexpr uint32_t SIT_BITMAP_BITS_PER_BYTE = 8;
constexpr uint32_t SEGMENTINFOS_PER_SIT = 2;
constexpr uint32_t SEGMENTINFOS_PER_NAT = 2;
constexpr uint32_t RESERVED_SEGMENTS_FACTOR = 2;
constexpr uint32_t RESERVED_MIN_SEGMENTS = 6;
constexpr uint32_t RESERVED_BASE_RATIO = 1;
constexpr uint32_t DEFAULT_INIT_VALUE = 1;
constexpr uint32_t DEFAULT_INIT_MINUS_ONE = -1;
constexpr uint32_t DEFAULT_INIT_ZERO = 0;
constexpr uint32_t SEGMENTS_PER_SECTION = 1;
constexpr uint32_t SECTIONS_PER_ZONE = 1;
constexpr uint32_t SEGMENTS_PER_ZONE = 1;
constexpr uint32_t ZONE_START_OFFSET_BLOCKS = 2;
ResizeOperator::ResizeOperator(CmdConfig &resizeConfig) : resizeConfig_(resizeConfig)
{
    config_ = std::make_shared<HmfsConfigData>();
    superBlockInfo_ = std::make_shared<HmfsSuperBlockInfo>();
    int ret = memset_s(config_.get(), sizeof(HmfsConfigData), 0, sizeof(HmfsConfigData));
    HMFS_CHECK_ONLY_LOG(ret == 0, "Failed to set HmfsConfigData");
    ret = memset_s(superBlockInfo_.get(), sizeof(HmfsSuperBlockInfo), 0, sizeof(HmfsSuperBlockInfo));
    HMFS_CHECK_ONLY_LOG(ret == 0, "Failed to set HmfsSuperBlockInfo");
    InitConfig();
    resizeDefrag_ = std::make_unique<ResizeDefrag>(this, superBlockInfo_, config_);
}

void ResizeOperator::InitConfig()
{
    config_->deviceNumber = DEFAULT_INIT_VALUE;
    config_->blockSectorCount = DEFAULT_SECTORS_PER_BLOCK;
    config_->segmentBlockCount = BLOCKS_PER_SEGMENT;
    config_->wantedTotalSectors = DEFAULT_INIT_MINUS_ONE;
    config_->wantedSectorSize = DEFAULT_INIT_MINUS_ONE;
    config_->preserveLimits = DEFAULT_INIT_VALUE;
    config_->noKernelCheck = DEFAULT_INIT_VALUE;
    for (uint32_t i = 0; i < MAX_DEVICE_COUNT; i++) {
        config_->devices[i].fd = DEFAULT_INIT_MINUS_ONE;
        config_->devices[i].sectorSize = DEFAULT_SECTOR_SIZE;
        config_->devices[i].endBlockId = DEFAULT_INIT_MINUS_ONE;
        config_->devices[i].zonedModel = HMFS_ZONED_NONE;
    }
    config_->segmentsPerSection = SEGMENTS_PER_SECTION;
    config_->sectionsPerZone = SECTIONS_PER_ZONE;
    config_->segmentsPerZone = SEGMENTS_PER_ZONE;
    config_->trim = DEFAULT_INIT_VALUE;
    config_->fixedTime = DEFAULT_INIT_MINUS_ONE;
    config_->fileEncoding = DEFAULT_INIT_ZERO;
    config_->fileEncodingFlags = DEFAULT_INIT_ZERO;
    config_->rootUid = getuid();
    config_->rootGid = getgid();
    config_->debugLevel = resizeConfig_.debugLevel;
    config_->force = resizeConfig_.force;
    config_->safeResize = resizeConfig_.safeResize;
    config_->targetSectors = resizeConfig_.targetSectors;
    config_->largeNatBitmap = resizeConfig_.largeNatBitmap;
    config_->fileEncoding = resizeConfig_.sEncoding;
    config_->fileEncodingFlags = resizeConfig_.sEncodingFlags;
    config_->feature = resizeConfig_.features;
    config_->newOverprovision = resizeConfig_.newOverprovision;
    config_->sectorSize = DEFAULT_SECTOR_SIZE;
    config_->blockSectorCount = HMFS_BLOCK_SIZE / DEFAULT_SECTOR_SIZE;
}

int32_t ResizeOperator::GetNewSuperBlock(SuperBlockData *superBlockData)
{
    HMFS_CHECK_ONLY_EXPER(superBlockData != nullptr, return EXIT_ERR_CODE);
    HMFS_DEBUG("Enter GetNewSuperBlock");
    uint32_t blockPerSeg = 1 << GetLeValue(superBlockData->logBlksPerSeg);
    SetLeValue(superBlockData->blockCount, config_->targetSectors >> GetLeValue(superBlockData->log2SectorsPerBlock));
    uint32_t segmentSizeBytes = 1 << (GetLeValue(superBlockData->logBlockSize) +
        GetLeValue(superBlockData->logBlksPerSeg));
    uint32_t segsPerZone = GetLeValue(superBlockData->segsPerSection) * GetLeValue(superBlockData->sectionsPerZone);
    uint32_t zoneSizeBytes = segmentSizeBytes * segsPerZone;
    uint64_t zoneAlignStartOffset = ((static_cast<uint64_t>(config_->startSector) * DEFAULT_SECTOR_SIZE +
        ZONE_START_OFFSET_BLOCKS * HMFS_BLOCK_SIZE + zoneSizeBytes - 1) / zoneSizeBytes * zoneSizeBytes -
        static_cast<uint64_t>(config_->startSector) * DEFAULT_SECTOR_SIZE);

    SetLeValue(superBlockData->segmentCount, (config_->targetSectors * config_->sectorSize - zoneAlignStartOffset) /
        segmentSizeBytes / config_->segmentsPerSection * config_->segmentsPerSection);

    if (config_->safeResize == 0) {
        HandleUnsafeResize(superBlockData, blockPerSeg, segsPerZone);
    }

    SetLeValue(superBlockData->segmentCountInMain, GetLeValue(superBlockData->segmentCount) -
        (GetLeValue(superBlockData->segmentCountInCP) + GetLeValue(superBlockData->segmentCountInSIT) +
        GetLeValue(superBlockData->segmentCountInNAT) + GetLeValue(superBlockData->segmentCountInSSA)));

    SetLeValue(superBlockData->sectionCount, GetLeValue(superBlockData->segmentCountInMain) /
        GetLeValue(superBlockData->segsPerSection));

    SetLeValue(superBlockData->segmentCountInMain, GetLeValue(superBlockData->sectionCount) *
        GetLeValue(superBlockData->segsPerSection));

    if (config_->newOverprovision == 0) {
        config_->newOverprovision = HmfsCommon::GetInstance().GetBestOverProvision(superBlockData);
    }
    config_->newReservedSegments = (RESERVED_SEGMENTS_FACTOR * (PERCENT_TIMES / config_->newOverprovision +
        RESERVED_BASE_RATIO) + RESERVED_MIN_SEGMENTS) * GetLeValue(superBlockData->segsPerSection);

    if ((GetLeValue(superBlockData->segmentCountInMain) - SEGMENT_RESERVED_OFFSET) < config_->newReservedSegments ||
        GetLeValue(superBlockData->segmentCountInMain) * blockPerSeg > GetLeValue(superBlockData->blockCount)) {
        HMFS_ERROR("Error: Device size is not sufficient for HMFS volume, more segment needed =%u",
            config_->newReservedSegments - (GetLeValue(superBlockData->segmentCountInMain) -
            SEGMENT_RESERVED_OFFSET));
        return EXIT_ERR_CODE;
    }
    return SUCCESS_CODE;
}

void ResizeOperator::HandleUnsafeResize(SuperBlockData *superBlockData, uint32_t blockPerSeg, uint32_t segsPerZone)
{
    HMFS_CHECK_ONLY_EXPER(superBlockData != nullptr, return);
    CalculateSitSegments(superBlockData, blockPerSeg);
    uint32_t maxNatBitmapSize = 0;
    CalculateNatSegments(superBlockData, blockPerSeg, maxNatBitmapSize);
    CalculateSitBitmapSize(superBlockData, blockPerSeg, segsPerZone, maxNatBitmapSize);
    CalculateSsaBlockId(superBlockData, blockPerSeg);
    CalculateMainBlockId(superBlockData, blockPerSeg, segsPerZone);
}

void ResizeOperator::CalculateSitSegments(SuperBlockData *superBlockData, uint32_t blockPerSeg)
{
    uint32_t blocksForSit = AlignUpCount(GetLeValue(superBlockData->segmentCount), SIT_ENTRIES_PER_BLOCK);
    uint32_t sitSegments = AlignUpCount(blocksForSit, config_->segmentBlockCount);
    SetLeValue(superBlockData->segmentCountInSIT, sitSegments * SEGMENTINFOS_PER_SIT);
    SetLeValue(superBlockData->natBlockId, GetLeValue(superBlockData->sitBlockId) +
        GetLeValue(superBlockData->segmentCountInSIT) * blockPerSeg);
}

void ResizeOperator::CalculateNatSegments(SuperBlockData *superBlockData, uint32_t blockPerSeg,
    uint32_t &maxNatBitmapSize)
{
    HMFS_CHECK_ONLY_EXPER(superBlockData != nullptr, return);
    uint32_t totalValidBlocks = (GetLeValue(superBlockData->segmentCount) -
        (GetLeValue(superBlockData->segmentCountInCP) +
        GetLeValue(superBlockData->segmentCountInSIT))) * blockPerSeg;
    uint32_t blocksForNat = AlignUpCount(totalValidBlocks, NAT_ENTRY_PER_BLOCK);
    if (config_->largeNatBitmap) {
        uint32_t natSegments = AlignUpCount(blocksForNat, config_->segmentBlockCount) *
            DEFAULT_NAT_ENTRY_RATIO / PERCENT_TIMES;
        SetLeValue(superBlockData->segmentCountInNAT, natSegments ? natSegments : 1);
        maxNatBitmapSize = (GetLeValue(superBlockData->segmentCountInNAT) <<
            GetLeValue(superBlockData->logBlksPerSeg)) / SIT_BITMAP_BITS_PER_BYTE;
        SetLeValue(superBlockData->segmentCountInNAT,
            GetLeValue(superBlockData->segmentCountInNAT) * SEGMENTINFOS_PER_NAT);
    } else {
        SetLeValue(superBlockData->segmentCountInNAT, AlignUpCount(blocksForNat, config_->segmentBlockCount));
        maxNatBitmapSize = 0;
    }
}

void ResizeOperator::CalculateSitBitmapSize(SuperBlockData *superBlockData, uint32_t blockPerSeg,
    uint32_t segsPerZone, uint32_t &maxNatBitmapSize)
{
    HMFS_CHECK_ONLY_EXPER(superBlockData != nullptr, return);
    uint32_t sitBitmapSize = ((GetLeValue(superBlockData->segmentCountInSIT) / SEGMENTINFOS_PER_SIT) <<
        GetLeValue(superBlockData->logBlksPerSeg)) / SIT_BITMAP_BITS_PER_BYTE;
    uint32_t maxSitBitmapSize = 0;
    if (sitBitmapSize > SIT_MAX_BITMAP_SIZE) {
        maxSitBitmapSize = SIT_MAX_BITMAP_SIZE;
    } else {
        maxSitBitmapSize = sitBitmapSize;
    }
    if (config_->largeNatBitmap) {
        if (maxSitBitmapSize + maxNatBitmapSize > CP_MAX_BITMAP_SIZE) {
            uint32_t diff = maxSitBitmapSize + maxNatBitmapSize - CP_MAX_BITMAP_SIZE;
            SetLeValue(superBlockData->checkPointPayload, AlignUpCount(diff, HMFS_BLOCK_SIZE));
        } else {
            SetLeValue(superBlockData->checkPointPayload, 0);
        }
    } else {
        if (maxSitBitmapSize > CP_MAX_SIT_BITMAP_SIZE) {
            maxNatBitmapSize = CP_MAX_BITMAP_SIZE;
            SetLeValue(superBlockData->checkPointPayload, AlignUpCount(maxSitBitmapSize, HMFS_BLOCK_SIZE));
        } else {
            maxNatBitmapSize = CP_MAX_BITMAP_SIZE - maxSitBitmapSize;
            SetLeValue(superBlockData->checkPointPayload, 0);
        }

        uint32_t maxNatSegments = (maxNatBitmapSize * BITS_PER_BYTE) >> GetLeValue(superBlockData->logBlksPerSeg);
        if (GetLeValue(superBlockData->segmentCountInNAT) > maxNatSegments) {
            SetLeValue(superBlockData->segmentCountInNAT, maxNatSegments);
        }
        SetLeValue(superBlockData->segmentCountInNAT,
            GetLeValue(superBlockData->segmentCountInNAT) * SEGMENTINFOS_PER_NAT);
    }
}

void ResizeOperator::CalculateSsaBlockId(SuperBlockData *superBlockData, uint32_t blockPerSeg)
{
    HMFS_CHECK_ONLY_EXPER(superBlockData != nullptr, return);
    SetLeValue(superBlockData->ssaBlockId, GetLeValue(superBlockData->natBlockId) +
        GetLeValue(superBlockData->segmentCountInNAT) * blockPerSeg);

    uint32_t totalValidBlocks = (GetLeValue(superBlockData->segmentCount) -
        (GetLeValue(superBlockData->segmentCountInCP) + GetLeValue(superBlockData->segmentCountInSIT) +
        GetLeValue(superBlockData->segmentCountInNAT))) * blockPerSeg;

    uint32_t blocksForSsa = (blockPerSeg > 0) ? (totalValidBlocks / blockPerSeg + 1) : 1;
    SetLeValue(superBlockData->segmentCountInSSA, AlignUpCount(blocksForSsa, config_->segmentBlockCount));
}

void ResizeOperator::CalculateMainBlockId(SuperBlockData *superBlockData, uint32_t blockPerSeg, uint32_t segsPerZone)
{
    HMFS_CHECK_ONLY_EXPER(superBlockData != nullptr, return);
    uint32_t totalMetaSegments = GetLeValue(superBlockData->segmentCountInCP) +
        GetLeValue(superBlockData->segmentCountInSIT) + GetLeValue(superBlockData->segmentCountInNAT) +
        GetLeValue(superBlockData->segmentCountInSSA);

    if (segsPerZone == 0) {
        HMFS_ERROR("Invalid parameter: segsPerZone cannot be 0.");
        return;
    }
    uint32_t diff = totalMetaSegments % segsPerZone;
    if (diff != 0) {
        SetLeValue(superBlockData->segmentCountInSSA, GetLeValue(superBlockData->segmentCountInSSA) +
            (segsPerZone - diff));
    }
    SetLeValue(superBlockData->mainBlockId, GetLeValue(superBlockData->ssaBlockId) +
        GetLeValue(superBlockData->segmentCountInSSA) * blockPerSeg);
}

int32_t ResizeOperator::ShrinkNats(SuperBlockData *newSuperBlockData)
{
    HMFS_DEBUG("Enter ShrinkNats");
    HMFS_CHECK_ONLY_EXPER(newSuperBlockData != nullptr, return EXIT_ERR_CODE);
    SuperBlockData *superBlockData = superBlockInfo_->rawSuper;
    NodeAddressTable *nat = superBlockInfo_->nodeAddrTable;
    uint32_t oldNatBlockAddr = GetLeValue(superBlockData->natBlockId);
    void *natBlock = malloc(BLOCK_SZ);
    HMFS_ASSERT(natBlock);
    void *zeroBlock = calloc(BLOCK_SZ, 1);
    HMFS_ASSERT_FREE(zeroBlock, natBlock);
    uint32_t natBlocks = GetLeValue(newSuperBlockData->segmentCountInNAT) >> 1;
    natBlocks = natBlocks << GetLeValue(superBlockData->logBlksPerSeg);
    int32_t newMaxNid = NAT_ENTRY_PER_BLOCK * natBlocks;

    for (int32_t nodeId = nat->maxNodeId - 1; nodeId > newMaxNid; nodeId -= NAT_ENTRY_PER_BLOCK) {
        unsigned long blockOffset = nodeId / NAT_ENTRY_PER_BLOCK;
        int32_t segmentOffset = blockOffset >> superBlockInfo_->logBlksPerSeg;
        unsigned long blockAddr = (unsigned long)(oldNatBlockAddr +
            (segmentOffset << superBlockInfo_->logBlksPerSeg << 1) +
            (blockOffset & ((1 << superBlockInfo_->logBlksPerSeg) - 1)));

        if (HmfsCommon::GetInstance().VerifyBit(blockOffset, nat->natBitmap)) {
            blockAddr += superBlockInfo_->blocksPerSeg;
        }

        int32_t ret = HmfsIo::GetInstance().DevReadBlock(natBlock, blockAddr);
        HMFS_ASSERT_FREE_PTRS(ret >= 0, natBlock, zeroBlock);

        if (memcmp(zeroBlock, natBlock, BLOCK_SZ) != 0) {
            free(natBlock);
            free(zeroBlock);
            return EXIT_ERR_CODE;
        }
    }
    nat->maxNodeId = newMaxNid;
    free(natBlock);
    free(zeroBlock);
    return SUCCESS_CODE;
}

int32_t ResizeOperator::GetSumEntry(uint32_t blockAddr, SummaryEntry *sumEntry)
{
    HMFS_CHECK_ONLY_EXPER(sumEntry != nullptr, return EXIT_ERR_CODE);
    int32_t type = 0;
    uint32_t sitNumber = GetSegmentNumber(superBlockInfo_, blockAddr);
    uint32_t blockOffsetFromMain = blockAddr - superBlockInfo_->segmentTable->mainBlockAddr;
    uint32_t offset = blockOffsetFromMain % (1 << superBlockInfo_->logBlksPerSeg);

    SummaryBlockData *summaryBlock = GetSumBlock(sitNumber, &type);
    int ret = memcpy_s(sumEntry, sizeof(SummaryEntry), &(summaryBlock->entries[offset]), sizeof(SummaryEntry));
    HMFS_CHECK_ONLY_LOG(ret == 0, "Failed to copy SummaryEntry");
    if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA || type == SEG_TYPE_MAX) {
        free(summaryBlock);
    }
    return type;
}

SummaryBlockData *ResizeOperator::GetSumBlock(uint32_t sitNumber, int32_t *retType)
{
    HMFS_CHECK_ONLY_EXPER(retType != nullptr, return nullptr);
    CheckPointData *checkPointData = superBlockInfo_->checkPointData;
    CurrentSegmentInfo *curSeg;
    *retType = SEG_TYPE_MAX;

    uint64_t ssaBlock = superBlockInfo_->segmentTable->ssaBlockAddr + sitNumber;
    for (uint32_t type = 0; type < CURSEG_NODE_TYPE_COUNT; type++) {
        if (sitNumber == GetLeValue(checkPointData->curNodeSegNo[type])) {
            curSeg = GetCurrentSegment(superBlockInfo_, CURSEG_NODE_HOT + type);
            if (curSeg->summaryBlockData->footer.entryType != SUM_TYPE_NODE) {
                HMFS_ERROR("sitNumber [0x%x] indicates a data segment, but should be node", sitNumber);
                *retType = -SEG_TYPE_CUR_NODE;
            } else {
                *retType = SEG_TYPE_CUR_NODE;
            }
            return curSeg->summaryBlockData;
        }
    }

    for (uint32_t type = 0; type < CURSEG_DATA_TYPE_COUNT; type++) {
        if (sitNumber == GetLeValue(checkPointData->curDataSegNo[type])) {
            curSeg = GetCurrentSegment(superBlockInfo_, type);
            if (curSeg->summaryBlockData->footer.entryType == SUM_TYPE_NODE) {
                HMFS_ERROR("sitNumber [0x%x] indicates a node segment, but should be data", sitNumber);
                *retType = -SEG_TYPE_CUR_DATA;
            } else {
                *retType = SEG_TYPE_CUR_DATA;
            }
            return curSeg->summaryBlockData;
        }
    }
    SummaryBlockData *summaryBlock = static_cast<SummaryBlockData *>(calloc(BLOCK_SZ, 1));
    HMFS_ASSERT(summaryBlock);

    int32_t ret = HmfsIo::GetInstance().DevReadBlock(summaryBlock, ssaBlock);
    HMFS_ASSERT(ret >= 0);

    if (summaryBlock->footer.entryType == SUM_TYPE_NODE) {
        *retType = SEG_TYPE_NODE;
    } else if (summaryBlock->footer.entryType == SUM_TYPE_DATA) {
        *retType = SEG_TYPE_DATA;
    }
    return summaryBlock;
}

void ResizeOperator::UpdateDataBlkaddr(uint32_t nodeId, uint16_t nodeBlockOffset, uint32_t newAddr)
{
    NodeData *nodeBlock = static_cast<NodeData *>(calloc(BLOCK_SZ, 1));
    HMFS_ASSERT(nodeBlock);
    NodeInfo ni = {};
    GetNodeInfo(superBlockInfo_, nodeId, &ni);
    uint32_t oldAddr = 0;
    int ret = HmfsIo::GetInstance().DevReadBlock(nodeBlock, ni.blockAddr);
    HMFS_ASSERT_FREE(ret >= 0, nodeBlock);
    if (nodeBlock->footer.nodeId == nodeBlock->footer.inodeNumber) {
        int blockOffset = HmfsCommon::GetInstance().GetExtraIsize(&nodeBlock->inode);
        oldAddr = LE32ToNative(nodeBlock->inode.dataBlocksAddr[blockOffset + nodeBlockOffset]);
        nodeBlock->inode.dataBlocksAddr[blockOffset + nodeBlockOffset] = NativeToLE32(newAddr);
        ret = HmfsCommon::GetInstance().WriteInode(nodeBlock, ni.blockAddr, config_->checksumSeed);
        HMFS_ASSERT_FREE(ret >= 0, nodeBlock);
    } else {
        oldAddr = LE32ToNative(nodeBlock->directNode.addr[nodeBlockOffset]);
        nodeBlock->directNode.addr[nodeBlockOffset] = NativeToLE32(newAddr);
        ret = HmfsIo::GetInstance().DevWriteBlock(nodeBlock, ni.blockAddr);
        HMFS_ASSERT_FREE(ret >= 0, nodeBlock);
    }

    if (nodeBlock->footer.nodeId != nodeBlock->footer.inodeNumber) {
        GetNodeInfo(superBlockInfo_, LE32ToNative(nodeBlock->footer.inodeNumber), &ni);
        ret = HmfsIo::GetInstance().DevReadBlock(nodeBlock, ni.blockAddr);
        HMFS_ASSERT_FREE(ret >= 0, nodeBlock);
    }

    uint32_t startAddr = LE32ToNative(nodeBlock->inode.largestExtent.blkAddr);
    uint32_t endAddr = startAddr + LE32ToNative(nodeBlock->inode.largestExtent.len);
    if (oldAddr >= startAddr && oldAddr < endAddr) {
        nodeBlock->inode.largestExtent.len = 0;
        HMFS_ASSERT_FREE(HmfsCommon::GetInstance().WriteInode(nodeBlock,
            ni.blockAddr, config_->checksumSeed) >= 0, nodeBlock);
    }
    free(nodeBlock);
}

void ResizeOperator::UpdateNatBlkaddr(uint32_t inodeNumber, uint32_t nodeId, uint32_t newaddr)
{
     NatBlockData *natBlock = static_cast<NatBlockData *>(calloc(BLOCK_SZ, 1));
     HMFS_ASSERT(natBlock);
    uint32_t entryOffset = nodeId % NAT_ENTRY_PER_BLOCK;
    unsigned long blockAddr = CurrentNatAddr(superBlockInfo_, nodeId);
    int ret = HmfsIo::GetInstance().DevReadBlock(natBlock, blockAddr);
    HMFS_ASSERT_FREE(ret >= 0, natBlock);

    if (inodeNumber) {
        natBlock->entries[entryOffset].inodeNumber = NativeToLE32(inodeNumber);
    }
    natBlock->entries[entryOffset].blockId = NativeToLE32(newaddr);
    ret = HmfsIo::GetInstance().DevWriteBlock(natBlock, blockAddr);
    free(natBlock);
    HMFS_ASSERT(ret >= 0);
}

int32_t ResizeOperator::MigrateMainArea(uint32_t offset)
{
    HMFS_DEBUG("Enter MigrateMainArea");
    uint8_t *raw = static_cast<uint8_t *>(calloc(BLOCK_SZ, 1));
    HMFS_ASSERT(raw);
    SegmentInfoTable *smInfo = superBlockInfo_->segmentTable;
    uint32_t smMainSeg = smInfo->mainSegments;

    for (int32_t i = smMainSeg - 1; i >= 0; i--) {
        SegmentEntry *sitEntry = GetSegEntry(superBlockInfo_, i);
        if (sitEntry->validBlocks == 0) {
            continue;
        }
        for (int32_t j = superBlockInfo_->blocksPerSeg - 1; j >= 0; j--) {
            if (!HmfsCommon::GetInstance().VerifyBit(j, sitEntry->currentValidBitmap)) {
                continue;
            }
            uint32_t from = START_BLOCK(superBlockInfo_, i) + j;
            int32_t ret = HmfsIo::GetInstance().DevReadBlock(raw, from);
            HMFS_ASSERT_FREE(ret >= 0, raw);

            uint32_t to = from + offset;
            ret = HmfsIo::GetInstance().DevWriteBlock(raw, to);
            HMFS_ASSERT_FREE(ret >= 0, raw);
            SummaryEntry sum = {};
            GetSumEntry(from, &sum);

            if (IsDataSegement(sitEntry->type)) {
                UpdateDataBlkaddr(LE32ToNative(sum.nodeId), LE16ToNative(sum.nodeBlockOffset), to);
            } else {
                UpdateNatBlkaddr(0, LE32ToNative(sum.nodeId), to);
            }
        }
    }
    free(raw);
    HMFS_INFO("Done to migrate Main area: main_blkaddr = 0x%x -> 0x%x\n",
        START_BLOCK(superBlockInfo_, 0), START_BLOCK(superBlockInfo_, 0) + offset);
    return SUCCESS_CODE;
}

void ResizeOperator::MoveSsa(uint32_t sitNumber, uint32_t newSumBlkAddr)
{
    int32_t type = 0;
    SummaryBlockData *summaryBlock = GetSumBlock(sitNumber, &type);
    if (type < SEG_TYPE_MAX) {
        int32_t ret = HmfsIo::GetInstance().DevWriteBlock(summaryBlock, newSumBlkAddr);
        HMFS_ASSERT(ret >= 0);
    }
    if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA || type == SEG_TYPE_MAX) {
        free(summaryBlock);
    }
    HMFS_DEBUG("Done to migrate SSA blocks");
}

int32_t ResizeOperator::MigrateSsa(SuperBlockData *newSuperBlockData, uint32_t offset)
{
    HMFS_DEBUG("Enter MigrateSsa");
    if (newSuperBlockData == nullptr) {
        return EXIT_ERR_CODE;
    }
    SuperBlockData *superBlockData = superBlockInfo_->rawSuper;
    uint32_t oldSumBlkaddr = GetLeValue(superBlockData->ssaBlockId);
    uint32_t newSumBlkaddr = GetLeValue(newSuperBlockData->ssaBlockId);
    uint32_t endSumBlockAddr = GetLeValue(newSuperBlockData->mainBlockId);
    uint32_t expandSummaryBlockAddr = newSumBlkaddr + MAIN_SEGS(superBlockInfo_) - offset;
    uint32_t blockAddr = 0;
    int32_t ret = -1;
    void *zeroBlock = calloc(BLOCK_SZ, 1);
    HMFS_ASSERT(zeroBlock);
    if (offset && newSumBlkaddr < oldSumBlkaddr + offset) {
        blockAddr = newSumBlkaddr;
        while (blockAddr < endSumBlockAddr) {
            if (blockAddr < expandSummaryBlockAddr) {
                MoveSsa(offset++, blockAddr++);
            } else {
                ret = HmfsIo::GetInstance().DevWriteBlock(zeroBlock, blockAddr++);
                HMFS_ASSERT_FREE(ret >= 0, zeroBlock);
            }
        }
    } else {
        blockAddr = endSumBlockAddr - 1;
        offset = MAIN_SEGS(superBlockInfo_) - 1;
        while (blockAddr >= newSumBlkaddr) {
            if (blockAddr >= expandSummaryBlockAddr) {
                ret = HmfsIo::GetInstance().DevWriteBlock(zeroBlock, blockAddr--);
                HMFS_ASSERT_FREE(ret >= 0, zeroBlock);
            } else {
                MoveSsa(offset--, blockAddr--);
            }
        }
    }
    free(zeroBlock);
    HMFS_INFO("Done to migrate SSA blocks: sum_blkaddr = 0x%x -> 0x%x\n", oldSumBlkaddr, newSumBlkaddr);
    return SUCCESS_CODE;
}

int32_t ResizeOperator::MigrateNat(SuperBlockData *newSuperBlockData)
{
    HMFS_DEBUG("Enter MigrateNat");
    if (newSuperBlockData == nullptr) {
        return EXIT_ERR_CODE;
    }
    SuperBlockData *superBlockData = superBlockInfo_->rawSuper;
    NodeAddressTable *nat = superBlockInfo_->nodeAddrTable;
    uint32_t oldNatBlockAddr = GetLeValue(superBlockData->natBlockId);
    uint32_t newNatBlkaddr = GetLeValue(newSuperBlockData->natBlockId);
    void *natBlock = malloc(BLOCK_SZ);
    HMFS_ASSERT(natBlock);
    for (int32_t nodeId = nat->maxNodeId - 1; nodeId >= 0; nodeId -= NAT_ENTRY_PER_BLOCK) {
        unsigned long blockOffset = nodeId / NAT_ENTRY_PER_BLOCK;
        int32_t segmentOffset = blockOffset >> superBlockInfo_->logBlksPerSeg;
        unsigned long blockAddr = static_cast<unsigned long>(oldNatBlockAddr + (segmentOffset <<
            superBlockInfo_->logBlksPerSeg << 1) + (blockOffset & ((1 << superBlockInfo_->logBlksPerSeg) - 1)));
        if (HmfsCommon::GetInstance().VerifyBit(blockOffset, nat->natBitmap)) {
            blockAddr += superBlockInfo_->blocksPerSeg;
            HmfsCommon::GetInstance().ClearBit(blockOffset, nat->natBitmap);
        }
        int32_t ret = HmfsIo::GetInstance().DevReadBlock(natBlock, blockAddr);
        HMFS_ASSERT_FREE(ret >= 0, natBlock);
        blockAddr = static_cast<unsigned long>(newNatBlkaddr + (segmentOffset << superBlockInfo_->logBlksPerSeg <<
            1) + (blockOffset & ((1 << superBlockInfo_->logBlksPerSeg) - 1)));
        ret = HmfsIo::GetInstance().DevWriteBlock(natBlock, blockAddr);
        HMFS_ASSERT_FREE(ret >= 0, natBlock);
    }
    int retCode = memset_s(natBlock, BLOCK_SZ, 0, BLOCK_SZ);
    HMFS_CHECK_ONLY_LOG(retCode == 0, "Failed to set natBlock");
    uint32_t natBlocks = GetLeValue(newSuperBlockData->segmentCountInNAT) >> 1;
    natBlocks = natBlocks << GetLeValue(superBlockData->logBlksPerSeg);
    int32_t newMaxNid = NAT_ENTRY_PER_BLOCK * natBlocks;

    HMFS_INFO("Write NAT block: %x->%x, max_nid=%x->%x\n",
        oldNatBlockAddr, newNatBlkaddr, GetLeValue(superBlockData->segmentCountInNAT),
        GetLeValue(newSuperBlockData->segmentCountInNAT));

    for (int32_t nodeId = nat->maxNodeId; nodeId < newMaxNid; nodeId += NAT_ENTRY_PER_BLOCK) {
        unsigned long blockOffset = nodeId / NAT_ENTRY_PER_BLOCK;
        int32_t segmentOffset = blockOffset >> superBlockInfo_->logBlksPerSeg;
        unsigned long blockAddr = static_cast<unsigned long>(newNatBlkaddr + (segmentOffset <<
            superBlockInfo_->logBlksPerSeg << 1) + (blockOffset & ((1 << superBlockInfo_->logBlksPerSeg) - 1)));
        int32_t ret = HmfsIo::GetInstance().DevWriteBlock(natBlock, blockAddr);
        HMFS_ASSERT_FREE(ret >= 0, natBlock);
        HMFS_DEBUG("Write NAT: %lx\n", blockAddr);
    }
    free(natBlock);
    HMFS_INFO("Done to migrate NAT blocks: nat_blkaddr = 0x%x -> 0x%x\n", oldNatBlockAddr, newNatBlkaddr);
    return SUCCESS_CODE;
}

int32_t ResizeOperator::MigrateSit(SuperBlockData *newSuperBlockData, uint32_t offset)
{
    HMFS_DEBUG("Enter MigrateSit");
    HMFS_CHECK_ONLY_EXPER(newSuperBlockData != nullptr, return EXIT_ERR_CODE);
    SitInfo *sitInfo = superBlockInfo_->segmentTable->sitInfo;
    uint32_t previousOffset = 0;
    uint32_t sitBlks = GetLeValue(newSuperBlockData->segmentCountInSIT) << (superBlockInfo_->logBlksPerSeg - 1);
    SitBlockData *sitBlock = static_cast<SitBlockData *>(calloc(BLOCK_SZ, 1));
    HMFS_ASSERT(sitBlock);
    for (uint32_t index = 0; index < sitBlks; index++) {
        int32_t ret = HmfsIo::GetInstance().DevWriteBlock(sitBlock, GetLeValue(newSuperBlockData->sitBlockId) + index);
        HMFS_ASSERT_FREE(ret >= 0, sitBlock);
        HMFS_DEBUG("Write zero sit: %x", GetLeValue(newSuperBlockData->sitBlockId) + index);
    }
    uint32_t blockOffset = 0;
    uint32_t blockAddr = 0;
    for (uint32_t sitNumber = 0; sitNumber < MAIN_SEGS(superBlockInfo_); sitNumber++) {
        SegmentEntry *sitEntry = GetSegEntry(superBlockInfo_, sitNumber);
        if (sitNumber < offset) {
            HMFS_ASSERT_FREE(sitEntry->validBlocks == 0, sitBlock);
            continue;
        }
        blockOffset = SIT_BLOCK_OFFSET(sitNumber - offset);
        if (blockOffset != previousOffset) {
            blockAddr = GetLeValue(newSuperBlockData->sitBlockId) + previousOffset;
            int32_t ret = HmfsIo::GetInstance().DevWriteBlock(sitBlock, blockAddr);
            HMFS_ASSERT_FREE(ret >= 0, sitBlock);
            HMFS_DEBUG("Write validId sit: %x", blockAddr);

            previousOffset = blockOffset;
            int retCode = memset_s(sitBlock, BLOCK_SZ, 0, BLOCK_SZ);
            HMFS_CHECK_ONLY_LOG(retCode == 0, "Failed to set sitBlock");
        }
        uint32_t sitEntryOffSet = (sitNumber - offset) % sitInfo->sentsPerBlock;
        SitEntry *sit = &sitBlock->entries[sitEntryOffSet];
        int retCode = memcpy_s(sit->blockBitmap, SIT_VBLOCK_MAP_SIZE,
            sitEntry->currentValidBitmap, SIT_VBLOCK_MAP_SIZE);
        HMFS_CHECK_ONLY_LOG(retCode == 0, "Failed to copy sit bitmap");
        sit->usedBlocks = NativeToLE16((sitEntry->type << SIT_USER_BLOCK_COUNT_SHIFT) | sitEntry->validBlocks);
    }
    blockAddr = GetLeValue(newSuperBlockData->sitBlockId) + blockOffset;
    int32_t ret = HmfsIo::GetInstance().DevWriteBlock(sitBlock, blockAddr);
    free(sitBlock);
    HMFS_DEBUG("Write validId sit: %x", blockAddr);
    HMFS_ASSERT(ret >= 0);
    HMFS_INFO("Done to restore new SIT blocks: 0x%x\n", GetLeValue(newSuperBlockData->sitBlockId));
    return SUCCESS_CODE;
}

void ResizeOperator::RebuildCheckpoint(SuperBlockData *newSuperBlockData, uint32_t offset)
{
    HMFS_DEBUG("Enter RebuildCheckpoint");
    HMFS_CHECK_ONLY_EXPER(newSuperBlockData != nullptr, return);
    CheckPointData *checkPointData = superBlockInfo_->checkPointData;
    SetLeValue(checkPointData->reservedSegmentCount, config_->newReservedSegments);
    SetLeValue(checkPointData->overprovisionSegmentCount, (GetLeValue(newSuperBlockData->segmentCountInMain) -
        GetLeValue(checkPointData->reservedSegmentCount)) * config_->newOverprovision / PERCENT_TIMES);
    SetLeValue(checkPointData->overprovisionSegmentCount, GetLeValue(checkPointData->overprovisionSegmentCount) +
        GetLeValue(checkPointData->reservedSegmentCount));

    HMFS_INFO("Overprovision ratio = %.3lf%%\n", config_->newOverprovision);
    HMFS_INFO("Overprovision segments = %u (GC reserved = %u)\n",
        GetLeValue(checkPointData->overprovisionSegmentCount), config_->newReservedSegments);

    uint32_t freeSegmentCount = GetFreeSegments(superBlockInfo_, config_);
    SuperBlockData *superBlockData = superBlockInfo_->rawSuper;
    uint32_t newSegmentCount = GetLeValue(newSuperBlockData->segmentCountInMain) -
        GetLeValue(superBlockData->segmentCountInMain);

    SetLeValue(checkPointData->freeSegmentCount, freeSegmentCount + newSegmentCount);
    SetLeValue(checkPointData->userBlockCount, ((GetLeValue(newSuperBlockData->segmentCountInMain) -
        GetLeValue(checkPointData->overprovisionSegmentCount)) * config_->segmentBlockCount));

    uint32_t orphanBlocks = 0;
    if (IsCheckpointFlags(checkPointData, CP_FLAG_ORPHAN_PRESENT)) {
        orphanBlocks = LE32ToNative(checkPointData->summaryStartBlock) - 1;
    }
    SetLeValue(checkPointData->summaryStartBlock, 1 + GetLeValue(newSuperBlockData->checkPointPayload));
    SetLeValue(checkPointData->checkPointPackBlockCount, CP_PACK_BASE_BLOCK_COUNT + orphanBlocks +
        GetLeValue(newSuperBlockData->checkPointPayload));

    UpdateCheckpointSegments(superBlockData, checkPointData, newSuperBlockData, offset, orphanBlocks);
}

void ResizeOperator::UpdateCheckpointSegments(SuperBlockData *superBlockData,
    CheckPointData *checkPointData, SuperBlockData *newSuperBlockData, uint32_t offset, uint32_t orphanBlocks)
{
    HMFS_CHECK_ONLY_EXPER(superBlockData != nullptr && checkPointData != nullptr &&
        newSuperBlockData != nullptr, return);
    UpdateCurrentSegments(checkPointData, offset);
    UpdateVersionBitmapSizes(checkPointData, newSuperBlockData);
    uint32_t flags = 0;
    UpdateCheckpointFlags(checkPointData, newSuperBlockData, flags);
    WriteNewCheckpoint(superBlockData, checkPointData, newSuperBlockData, orphanBlocks, flags);
}

void ResizeOperator::UpdateCurrentSegments(CheckPointData *checkPointData, uint32_t offset)
{
    HMFS_CHECK_ONLY_EXPER(checkPointData != nullptr, return);
    for (int32_t i = 0; i < CURSEG_TYPE_MAX; i++) {
        if (i < CURSEG_NODE_HOT) {
            SetLeValue(checkPointData->curDataSegNo[i], GetCurrentSegment(superBlockInfo_, i)->segmentNumber - offset);
        } else {
            int32_t n = i - CURSEG_NODE_HOT;
            SetLeValue(checkPointData->curNodeSegNo[n], GetCurrentSegment(superBlockInfo_, i)->segmentNumber - offset);
        }
    }
}

void ResizeOperator::UpdateVersionBitmapSizes(CheckPointData *checkPointData, SuperBlockData *newSuperBlockData)
{
    HMFS_CHECK_ONLY_EXPER(checkPointData != nullptr && newSuperBlockData != nullptr, return);
    SetLeValue(checkPointData->sitVersionBitmapSize, ((GetLeValue(newSuperBlockData->segmentCountInSIT) /
        SEGMENTINFOS_PER_SIT) << GetLeValue(newSuperBlockData->logBlksPerSeg)) / SIT_BITMAP_BITS_PER_BYTE);
    SetLeValue(checkPointData->natVersionBitmapSize, ((GetLeValue(newSuperBlockData->segmentCountInNAT) /
        SEGMENTINFOS_PER_NAT) << GetLeValue(newSuperBlockData->logBlksPerSeg)) / SIT_BITMAP_BITS_PER_BYTE);
}

void ResizeOperator::UpdateCheckpointFlags(CheckPointData *checkPointData, SuperBlockData *newSuperBlockData,
    uint32_t &flags)
{
    HMFS_CHECK_ONLY_EXPER(checkPointData != nullptr && newSuperBlockData != nullptr, return);
    flags = UpdateNatBitsFlags(newSuperBlockData, checkPointData, GetLeValue(checkPointData->checkPointFlags));
    if (config_->largeNatBitmap) {
        flags |= CP_FLAG_LARGE_NAT_BITMAP;
    }
    if (flags & CP_FLAG_COMPACT_SUM) {
        flags &= ~CP_FLAG_COMPACT_SUM;
    }
    if (flags & CP_FLAG_LARGE_NAT_BITMAP) {
        SetLeValue(checkPointData->checksumOffset, CP_MIN_CHECKSUM_OFFSET);
    } else {
        SetLeValue(checkPointData->checksumOffset, CP_CHECKSUM_OFFSET);
    }
    SetLeValue(checkPointData->checkPointFlags, flags);
}

void ResizeOperator::WriteNewCheckpoint(SuperBlockData *superBlockData, CheckPointData *checkPointData,
    SuperBlockData *newSuperBlockData, uint32_t orphanBlocks, uint32_t flags)
{
    size_t copySize = reinterpret_cast<unsigned char *>(checkPointData->sitNatVersionBitmap) -
        reinterpret_cast<unsigned char *>(checkPointData);
    uint32_t newCheckPointBlocks = 1 + GetLeValue(newSuperBlockData->checkPointPayload);
    CheckPointData *newCheckPoint = static_cast<CheckPointData *>(calloc(newCheckPointBlocks * BLOCK_SZ, 1));
    HMFS_ASSERT(newCheckPoint);
    HMFS_CHECK_ONLY_EXPER(memcpy_s(newCheckPoint, copySize, checkPointData, copySize) == 0, return);
    if (config_->safeResize) {
        size_t copySizeEnd = HMFS_BLOCK_SIZE - CP_BITMAP_OFFSET;
        int retCodes = memcpy_s(reinterpret_cast<unsigned char *>(newCheckPoint) + CP_BITMAP_OFFSET, copySizeEnd,
            reinterpret_cast<unsigned char *>(checkPointData) + CP_BITMAP_OFFSET, copySizeEnd);
        HMFS_CHECK_ONLY_LOG(retCodes == 0, "Failed to copy new checkpoint end");
    }
    unsigned long long checkPointVersion = GetLeValue(checkPointData->checkPointVersion);
    newCheckPoint->checkPointVersion = NativeToLE64(checkPointVersion + 1);
    uint32_t crc = HmfsCommon::GetInstance().GetCheckpointChksum(newCheckPoint);
    *(reinterpret_cast<uint32_t *>((reinterpret_cast<unsigned char *>(newCheckPoint) +
        GetLeValue(checkPointData->checksumOffset)))) = NativeToLE32(crc);

    uint32_t oldCheckPointBlockId = GetLeValue(superBlockData->checkPointBlockId);
    uint32_t newCheckPointBlockId = oldCheckPointBlockId;
    if (superBlockInfo_->currentCheckPointId == CHECKPOINT_TWO) {
        oldCheckPointBlockId += 1 << GetLeValue(superBlockData->logBlksPerSeg);
    } else {
        newCheckPointBlockId += 1 << GetLeValue(superBlockData->logBlksPerSeg);
    }
    int32_t ret = HmfsIo::GetInstance().DevWriteBlock(newCheckPoint, newCheckPointBlockId++);
    HMFS_ASSERT_FREE(ret >= 0, newCheckPoint);
    uint8_t *buf = static_cast<uint8_t *>(malloc(BLOCK_SZ));
    HMFS_ASSERT(buf);
    HMFS_CHECK_ONLY_EXPER(memset_s(buf, BLOCK_SZ, 0, BLOCK_SZ) == 0, free(buf); return);

    HandleOrphanBlocksAndWriteSegments(buf, oldCheckPointBlockId, newCheckPointBlockId,
        orphanBlocks, newSuperBlockData);

    ret = HmfsIo::GetInstance().DevWriteBlock(newCheckPoint, newCheckPointBlockId++);
    HMFS_ASSERT_FREE_PTRS(ret >= 0, newCheckPoint, buf);

#ifndef HMFS_TOOLS_ARM64
    if (flags & CP_FLAG_NAT_BITS) {
        WriteNatBits(newSuperBlockData, newCheckPoint,
            superBlockInfo_->currentCheckPointId == CHECKPOINT_ONE ? CHECKPOINT_TWO : CHECKPOINT_ONE);
    }
#endif
    HMFS_CHECK_ONLY_EXPER(memset_s(buf, BLOCK_SZ, 0, BLOCK_SZ) == 0, free(buf); return);
    ret = HmfsIo::GetInstance().DevWriteBlock(buf, oldCheckPointBlockId);
    HMFS_ASSERT(ret >= 0);
    HMFS_INFO("Done to rebuild checkpoint blocks\n");
}

void ResizeOperator::HandleOrphanBlocksAndWriteSegments(uint8_t *buf, uint32_t oldCheckPointBlockId,
    uint32_t &newCheckPointBlockId, uint32_t orphanBlocks, SuperBlockData *newSuperBlockData)
{
    HMFS_CHECK_ONLY_EXPER(buf != nullptr && newSuperBlockData != nullptr, return);
    for (uint32_t i = 0; i < orphanBlocks; i++) {
        uint32_t orphanBlocksNumber = oldCheckPointBlockId + 1 + GetLeValue(newSuperBlockData->checkPointPayload);
        int32_t ret = HmfsIo::GetInstance().DevReadBlock(buf, orphanBlocksNumber++);
        HMFS_ASSERT(ret >= 0);
        ret = HmfsIo::GetInstance().DevWriteBlock(buf, newCheckPointBlockId++);
        HMFS_ASSERT(ret >= 0);
    }

    for (int32_t i = 0; i < CURSEG_TYPE_MAX; i++) {
        CurrentSegmentInfo *curSeg = GetCurrentSegment(superBlockInfo_, i);
        int32_t ret = HmfsIo::GetInstance().DevWriteBlock(curSeg->summaryBlockData, newCheckPointBlockId++);
        HMFS_ASSERT(ret >= 0);
    }
}

int32_t ResizeOperator::HmfsResizeCheck(SuperBlockData *newSuperBlockData)
{
    HMFS_CHECK_ONLY_EXPER(newSuperBlockData != nullptr, return EXIT_ERR_CODE);
    CheckPointData *checkPointData = superBlockInfo_->checkPointData;
    uint32_t overprovisionSegmentCount = (GetLeValue(newSuperBlockData->segmentCountInMain) -
        config_->newReservedSegments) * config_->newOverprovision / PERCENT_TIMES;
    overprovisionSegmentCount += config_->newReservedSegments;

    uint32_t userBlockCount = (GetLeValue(newSuperBlockData->segmentCountInMain) - overprovisionSegmentCount) *
        config_->segmentBlockCount;
    if (GetLeValue(checkPointData->validBlockCount) > userBlockCount) {
        return EXIT_ERR_CODE;
    }
    return SUCCESS_CODE;
}

int32_t ResizeOperator::FlushNatJournalEntries()
{
    CurrentSegmentInfo *curSeg = GetCurrentSegment(superBlockInfo_, CURSEG_DATA_HOT);
    JournalEntry *journal = &curSeg->summaryBlockData->journal;
    NatBlockData *natBlock = static_cast<NatBlockData *>(calloc(BLOCK_SZ, 1));
    HMFS_ASSERT(natBlock);
    uint16_t natSum = NATS_IN_CURSUM(journal);
    int32_t i = 0;
    for (; i < natSum; i++) {
        uint32_t nodeId = LE32ToNative(NID_IN_JOURNAL(journal, i));

        int32_t entryOffset = nodeId % NAT_ENTRY_PER_BLOCK;
        unsigned long blockAddr = CurrentNatAddr(superBlockInfo_, nodeId);
        int32_t ret = HmfsIo::GetInstance().DevReadBlock(natBlock, blockAddr);
        HMFS_ASSERT_FREE(ret >= 0, natBlock);

        int retCode = memcpy_s(&natBlock->entries[entryOffset],
            sizeof(NatEntry), &NAT_IN_JOURNAL(journal, i), sizeof(NatEntry));
        HMFS_CHECK_ONLY_LOG(retCode == 0, "Failed to copy NatEntry");
        ret = HmfsIo::GetInstance().DevWriteBlock(natBlock, blockAddr);
        HMFS_ASSERT_FREE(ret >= 0, natBlock);
    }
    free(natBlock);
    journal->natCount = 0;
    return i;
}

void ResizeOperator::RewriteCurrentSitPage(uint32_t sitNumber, SitBlockData *sitBlock)
{
    HMFS_CHECK_ONLY_EXPER(sitBlock != nullptr, return);
    uint32_t blockAddr = CurrentSitAddr(superBlockInfo_, sitNumber);
    HMFS_ASSERT(HmfsIo::GetInstance().DevWriteBlock(sitBlock, blockAddr) >= 0);
}

int32_t ResizeOperator::FlushSitJournalEntries()
{
    CurrentSegmentInfo *curSeg = GetCurrentSegment(superBlockInfo_, CURSEG_DATA_COLD);
    JournalEntry *journal = &curSeg->summaryBlockData->journal;
    SitInfo *sitInfo = superBlockInfo_->segmentTable->sitInfo;
    SitBlockData *sitBlock = static_cast<SitBlockData *>(calloc(BLOCK_SZ, 1));
    HMFS_ASSERT(sitBlock);
    int32_t i = 0;
    for (i = 0; i < SITS_IN_CURSUM(journal); i++) {
        SitEntry *sit;
        SegmentEntry *sitEntry;

        uint32_t sitNumber = SEGNO_IN_JOURNAL(journal, i);
        sitEntry = GetSegEntry(superBlockInfo_, sitNumber);

        GetCurrentSitPage(superBlockInfo_, sitNumber, sitBlock);
        uint32_t sitEntryOffSet = sitNumber % sitInfo->sentsPerBlock;
        sit = &sitBlock->entries[sitEntryOffSet];
        int ret = memcpy_s(sit->blockBitmap, SIT_VBLOCK_MAP_SIZE, sitEntry->currentValidBitmap,
            SIT_VBLOCK_MAP_SIZE);
        HMFS_CHECK_ONLY_LOG(ret == 0, "Failed to copy sit bitmap");
        sit->usedBlocks = NativeToLE16((sitEntry->type << SIT_USER_BLOCK_COUNT_SHIFT) | sitEntry->validBlocks);
        sit->modificationTime = NativeToLE64(sitEntry->modificationTime);
        RewriteCurrentSitPage(sitNumber, sitBlock);
    }
    free(sitBlock);
    journal->sitCount = 0;
    return i;
}

void ResizeOperator::DuplicateCheckpoint()
{
    HMFS_DEBUG("Enter DuplicateCheckpoint");
    SuperBlockData *superBlockData = superBlockInfo_->rawSuper;
    unsigned long long dst = 0;
    unsigned long long src = 0;
    uint32_t segSize = 1 << GetLeValue(superBlockData->logBlksPerSeg);
    if (superBlockInfo_->checkPointBackuped) {
        return;
    }
    void *buf = malloc(HMFS_BLOCK_SIZE * segSize);
    HMFS_ASSERT(buf);
    if (superBlockInfo_->currentCheckPointId == CHECKPOINT_ONE) {
        src = GetLeValue(superBlockData->checkPointBlockId);
        dst = src + segSize;
    } else {
        dst = GetLeValue(superBlockData->checkPointBlockId);
        src = dst + segSize;
    }

    int32_t ret = HmfsIo::GetInstance().DevRead(buf, src << HMFS_BLKSIZE_BITS, segSize << HMFS_BLKSIZE_BITS);
    HMFS_ASSERT_FREE(ret >= 0, buf);

    ret = HmfsIo::GetInstance().DevWrite(buf, dst << HMFS_BLKSIZE_BITS, segSize << HMFS_BLKSIZE_BITS);
    free(buf);
    HMFS_ASSERT(ret >= 0);

    ret = HmfsIo::GetInstance().HmfsFsyncDevice();
    HMFS_ASSERT(ret >= 0);

    superBlockInfo_->checkPointBackuped = 1;
    HMFS_INFO("Duplicate validId checkpoint to mirror position %llu -> %llu\n", src, dst);
}

uint32_t ResizeOperator::UpdateNatBitsFlags(SuperBlockData *superBlockData,
    CheckPointData *checkPointData, uint32_t flags)
{
#ifndef HMFS_TOOLS_ARM64
    HMFS_CHECK_ONLY_EXPER(superBlockData != nullptr && checkPointData != nullptr, return 0);
    constexpr uint32_t natBitsShift = 5;
    constexpr uint32_t natBitsExtra = 8;
    HMFS_CHECK_ONLY_EXPER(superBlockData != nullptr && checkPointData != nullptr, return 1);
    uint32_t natBitsBytes = GetLeValue(superBlockData->segmentCountInNAT) << natBitsShift;
    uint32_t natBitsBlocks = HmfsBytesToBlk((natBitsBytes << 1) + natBitsExtra + HMFS_BLOCK_SIZE - 1);
    if (GetLeValue(checkPointData->checkPointPackBlockCount) <= (1 << GetLeValue(superBlockData->logBlksPerSeg)) -
        natBitsBlocks) {
        flags |= CP_FLAG_NAT_BITS;
    } else {
        flags &= (~CP_FLAG_NAT_BITS);
    }
#endif
    return flags;
}

void ResizeOperator::PrepareNatBits(SuperBlockData *superBlockData, CheckPointData *checkPointData,
    uint8_t *natBits, uint8_t *fullNatBits, uint8_t *emptyNatBits)
{
    HMFS_CHECK_ONLY_EXPER(superBlockData != nullptr && checkPointData != nullptr && natBits != nullptr &&
        fullNatBits != nullptr && emptyNatBits != nullptr, return);
    NodeAddressTable *nat = superBlockInfo_->nodeAddrTable;
    uint32_t natBlocks = GetLeValue(superBlockData->segmentCountInNAT) <<
        (GetLeValue(superBlockData->logBlksPerSeg) - 1);
    uint32_t natBitsBytes = natBlocks / BITS_PER_BYTE;
    NatBlockData *natBlock = static_cast<NatBlockData *>(malloc(HMFS_BLOCK_SIZE));
    HMFS_ASSERT(natBlock);
    HMFS_CHECK_ONLY_EXPER(memset_s(fullNatBits, natBitsBytes, 0, natBitsBytes) == 0, return);
    HMFS_CHECK_ONLY_EXPER(memset_s(emptyNatBits, natBitsBytes, 0, natBitsBytes) == 0, return);
    for (uint32_t i = 0; i < natBlocks; i++) {
        int segmentOffset = i >> GetLeValue(superBlockData->logBlksPerSeg);
        int validId = 0;
        unsigned long blockAddr = static_cast<unsigned long>(GetLeValue(superBlockData->natBlockId) +
            (segmentOffset << GetLeValue(superBlockData->logBlksPerSeg) << 1) +
            (i & ((1 << GetLeValue(superBlockData->logBlksPerSeg)) - 1)));
        if (i < nat->natBlocks && HmfsCommon::GetInstance().VerifyBit(i, nat->natBitmap)) {
            blockAddr += (1 << GetLeValue(superBlockData->logBlksPerSeg));
        }
        int32_t ret = HmfsIo::GetInstance().DevReadBlock(natBlock, blockAddr);
        HMFS_ASSERT_FREE(ret >= 0, natBlock);
        for (uint32_t j = 0; j < NAT_ENTRY_PER_BLOCK; j++) {
            if ((i == 0 && j == 0) || natBlock->entries[j].blockId != NULL_ADDR) {
                validId++;
            }
        }
        if (validId == 0) {
            HmfsCommon::GetInstance().TestAndSetBitLe(i, emptyNatBits);
        } else if (validId == NAT_ENTRY_PER_BLOCK) {
            HmfsCommon::GetInstance().TestAndSetBitLe(i, fullNatBits);
        }
    }
    *(uint64_t *)natBits = HmfsCommon::GetInstance().GetCpCrc(checkPointData);
    free(natBlock);
}

void ResizeOperator::WriteNatBits(SuperBlockData *superBlockData, CheckPointData *checkPointData, int32_t set)
{
    HMFS_CHECK_ONLY_EXPER(superBlockData != nullptr && checkPointData != nullptr, return);
    uint32_t natBlocks = GetLeValue(superBlockData->segmentCountInNAT) <<
        (GetLeValue(superBlockData->logBlksPerSeg) - 1);
    uint32_t natBitsBytes = natBlocks / BITS_PER_BYTE;
    constexpr uint32_t natBitsHeaderSize = 8;
    uint32_t natBitsBlocks = HmfsBytesToBlk((natBitsBytes << 1) + natBitsHeaderSize + HMFS_BLOCK_SIZE - 1);
    unsigned char *natBits = static_cast<unsigned char *>(calloc(HMFS_BLOCK_SIZE, natBitsBlocks));
    HMFS_ASSERT(natBits);

    unsigned char *fullNatBits = natBits + natBitsHeaderSize;
    unsigned char *emptyNatBits = fullNatBits + natBitsBytes;
    PrepareNatBits(superBlockData, checkPointData, natBits, fullNatBits, emptyNatBits);
    uint32_t blockAddr = GetLeValue(superBlockData->segment0BlockId) + (set <<
        GetLeValue(superBlockData->logBlksPerSeg)) - natBitsBlocks;
    HMFS_INFO("Writing NAT bits pages, at offset 0x%08x\n", blockAddr);

    for (uint32_t i = 0; i < natBitsBlocks; i++) {
        if (HmfsIo::GetInstance().DevWriteBlock(natBits + i * HMFS_BLOCK_SIZE, blockAddr + i)) {
            HMFS_ERROR("Error: write NAT bits to disk!!!\n");
        }
    }
    free(natBits);
    HMFS_INFO("Write validId nat_bits in checkpoint\n");
}

void ResizeOperator::WriteCheckpoint()
{
    HMFS_DEBUG("Enter WriteCheckpoint");
    SuperBlockData *superBlockData = superBlockInfo_->rawSuper;
    CheckPointData *checkPointData = superBlockInfo_->checkPointData;
    uint32_t orphanBlocks = 0;
    uint32_t flags = CP_FLAG_UMOUNT;

    SetCheckPointFlags(checkPointData, flags, orphanBlocks);
    UpdateCheckPointData(checkPointData, superBlockData, orphanBlocks);
    WriteCheckPointData(checkPointData, superBlockData, orphanBlocks, flags);
}

void ResizeOperator::SetCheckPointFlags(CheckPointData *checkPointData, uint32_t &flags, uint32_t &orphanBlocks)
{
    HMFS_CHECK_ONLY_EXPER(checkPointData != nullptr, return);
    if (IsCheckpointFlags(checkPointData, CP_FLAG_ORPHAN_PRESENT)) {
        orphanBlocks = LE32ToNative(checkPointData->summaryStartBlock) - 1;
        flags |= CP_FLAG_ORPHAN_PRESENT;
    }
    if (IsCheckpointFlags(checkPointData, CP_FLAG_TRIMMED)) {
        flags |= CP_FLAG_TRIMMED;
    }
    if (IsCheckpointFlags(checkPointData, CP_FLAG_DISABLED)) {
        flags |= CP_FLAG_DISABLED;
    }
    if (IsCheckpointFlags(checkPointData, CP_FLAG_LARGE_NAT_BITMAP)) {
        flags |= CP_FLAG_LARGE_NAT_BITMAP;
        SetLeValue(checkPointData->checksumOffset, CP_MIN_CHECKSUM_OFFSET);
    } else {
        SetLeValue(checkPointData->checksumOffset, CP_CHECKSUM_OFFSET);
    }
}

void ResizeOperator::UpdateCheckPointData(CheckPointData *checkPointData, SuperBlockData *superBlockData,
    uint32_t orphanBlocks)
{
    HMFS_CHECK_ONLY_EXPER(superBlockData != nullptr && checkPointData != nullptr, return);
    SetLeValue(checkPointData->freeSegmentCount, GetFreeSegments(superBlockInfo_, config_));
    SetLeValue(checkPointData->validBlockCount, superBlockInfo_->totalValidBlockCount);
    SetLeValue(checkPointData->validNodeCount, superBlockInfo_->totalValidNodeCount);
    SetLeValue(checkPointData->validInodeCount, superBlockInfo_->totalValidInodeCount);
    SetLeValue(checkPointData->checkPointPackBlockCount, CP_PACK_BASE_BLOCK_COUNT + orphanBlocks +
        GetLeValue(superBlockData->checkPointPayload));
}

void ResizeOperator::WriteCheckPointData(CheckPointData *checkPointData, SuperBlockData *superBlockData,
    uint32_t orphanBlocks, uint32_t flags)
{
    HMFS_CHECK_ONLY_EXPER(superBlockData != nullptr && checkPointData != nullptr, return);
    flags = UpdateNatBitsFlags(superBlockData, checkPointData, flags);
    SetLeValue(checkPointData->checkPointFlags, flags);

    uint32_t crc = HmfsCommon::GetInstance().GetCheckpointChksum(checkPointData);
    *(reinterpret_cast<uint32_t *>(reinterpret_cast<unsigned char *>(checkPointData) +
        GetLeValue(checkPointData->checksumOffset))) = NativeToLE32(crc);

    unsigned long long checkPointBlockNumber = GetLeValue(superBlockData->checkPointBlockId);
    if (superBlockInfo_->currentCheckPointId == CHECKPOINT_TWO) {
        checkPointBlockNumber += 1 << GetLeValue(superBlockData->logBlksPerSeg);
    }
    int32_t ret = HmfsIo::GetInstance().DevWriteBlock(checkPointData, checkPointBlockNumber++);
    HMFS_ASSERT(ret >= 0);

    checkPointBlockNumber += GetLeValue(superBlockData->checkPointPayload);
    checkPointBlockNumber += orphanBlocks;

    WriteCurrentSegments(checkPointBlockNumber, superBlockData);

#ifndef HMFS_TOOLS_ARM64
    if (flags & CP_FLAG_NAT_BITS) {
        WriteNatBits(superBlockData, checkPointData, superBlockInfo_->currentCheckPointId);
    }
#endif
    ret = HmfsIo::GetInstance().HmfsFsyncDevice();
    HMFS_ASSERT(ret >= 0);
    ret = HmfsIo::GetInstance().DevWriteBlock(checkPointData, checkPointBlockNumber++);
    HMFS_ASSERT(ret >= 0);
    ret = HmfsIo::GetInstance().HmfsFsyncDevice();
    HMFS_ASSERT(ret >= 0);
}

void ResizeOperator::WriteCurrentSegments(unsigned long long &checkPointBlockNumber, SuperBlockData *superBlockData)
{
    HMFS_CHECK_ONLY_EXPER(superBlockData != nullptr, return);
    for (int32_t i = 0; i < CURSEG_TYPE_MAX; i++) {
        CurrentSegmentInfo *curSeg = GetCurrentSegment(superBlockInfo_, i);
        int32_t ret = HmfsIo::GetInstance().DevWriteBlock(curSeg->summaryBlockData, checkPointBlockNumber++);
        HMFS_ASSERT(ret >= 0);

        if (!(GetLeValue(superBlockData->features) & NativeToLE32(HMFS_FEATURE_RO))) {
            uint64_t ssaBlock = superBlockInfo_->segmentTable->ssaBlockAddr + curSeg->segmentNumber;
            ret = HmfsIo::GetInstance().DevWriteBlock(curSeg->summaryBlockData, ssaBlock);
            HMFS_ASSERT(ret >= 0);
        }
    }
}

void ResizeOperator::DupWriteCheckpoints()
{
    DuplicateCheckpoint();
    superBlockInfo_->currentCheckPointId = CHECKPOINT_ONE;
    WriteCheckpoint();
}

void ResizeOperator::FlushJournalEntries()
{
    HMFS_DEBUG("Enter FlushJournalEntries");
    int32_t natCount = FlushNatJournalEntries();
    int32_t sitCount = FlushSitJournalEntries();
    if (natCount || sitCount) {
        DupWriteCheckpoints();
    }
}

int32_t ResizeOperator::HmfsResizeExpand()
{
    HMFS_DEBUG("Enter HmfsResizeExpand");
    SuperBlockData *superBlockData = superBlockInfo_->rawSuper;
    SuperBlockData superBlockRaw;
    SuperBlockData *newSuperBlock = &superBlockRaw;
    FlushJournalEntries();
    HMFS_CHECK_ONLY_EXPER(memcpy_s(newSuperBlock, sizeof(*newSuperBlock), superBlockData, sizeof(*newSuperBlock)) == 0,
        return EXIT_ERR_CODE);
    if (GetNewSuperBlock(newSuperBlock)) {
        return EXIT_ERR_CODE;
    }
    if (HmfsResizeCheck(newSuperBlock) < 0) {
        return EXIT_ERR_CODE;
    }
    int32_t ret = -1;
    if (GetLeValue(superBlockData->segmentCountInNAT) > GetLeValue(newSuperBlock->segmentCountInNAT)) {
        ret = ShrinkNats(newSuperBlock);
        if (ret != SUCCESS_CODE) {
            HMFS_ERROR("Error: Failed to shrink NATs\n");
            return ret;
        }
    }

    uint32_t oldMainBlockAddr = GetLeValue(superBlockData->mainBlockId);
    uint32_t newMainBlockAddr = GetLeValue(newSuperBlock->mainBlockId);
    uint32_t offset = newMainBlockAddr - oldMainBlockAddr;
    uint32_t endBlockAddr = (GetLeValue(superBlockData->segmentCountInMain) <<
        GetLeValue(superBlockData->logBlksPerSeg)) + GetLeValue(superBlockData->mainBlockId);

    ret = -EAGAIN;
    uint32_t offsetSeg = 0;
    if (newMainBlockAddr < endBlockAddr) {
        ret = resizeDefrag_->HmfsDefragment(oldMainBlockAddr, offset, newMainBlockAddr, 0);
        if (ret == SUCCESS_CODE) {
            offsetSeg = offset >> GetLeValue(superBlockData->logBlksPerSeg);
        }
        HMFS_INFO("Try to do defragement: %s\n", ret ? "Skip" : "Done");
    }
    if (ret != SUCCESS_CODE) {
        MigrateMainArea(offset);
    }
    HMFS_CHECK_ONLY_LOG(MigrateSsa(newSuperBlock, offsetSeg) == SUCCESS_CODE, "Failed to MigrateSsa");
    HMFS_CHECK_ONLY_LOG(MigrateNat(newSuperBlock) == SUCCESS_CODE, "Failed to MigrateNat");
    HMFS_CHECK_ONLY_LOG(MigrateSit(newSuperBlock, offsetSeg) == SUCCESS_CODE, "Failed to MigrateSit");
    RebuildCheckpoint(newSuperBlock, offsetSeg);
    UpdateSuperBlock(newSuperBlock, SUPER_BLOCK_MASK_ALL);
    return SUCCESS_CODE;
}

int32_t ResizeOperator::HmfsResizeShrink()
{
    HMFS_DEBUG("Enter HmfsResizeShrink");
    SuperBlockData *superBlockData = superBlockInfo_->rawSuper;
    SuperBlockData superBlockRaw;
    SuperBlockData *newSuperBlock = &superBlockRaw;
    int32_t ret = -1;
    FlushJournalEntries();
    HMFS_CHECK_ONLY_EXPER(memcpy_s(newSuperBlock, sizeof(*newSuperBlock), superBlockData, sizeof(*newSuperBlock)) == 0,
        return EXIT_ERR_CODE);
    if (GetNewSuperBlock(newSuperBlock) != SUCCESS_CODE) {
        return EXIT_ERR_CODE;
    }
    if (HmfsResizeCheck(newSuperBlock) < 0) {
        return EXIT_ERR_CODE;
    }
    if (GetLeValue(superBlockData->segmentCountInNAT) > GetLeValue(newSuperBlock->segmentCountInNAT)) {
        ret = ShrinkNats(newSuperBlock);
        if (ret != SUCCESS_CODE) {
            HMFS_ERROR("Error: Failed to shrink NATs\n");
            return ret;
        }
    }

    uint32_t oldMainBlockAddr = GetLeValue(superBlockData->mainBlockId);
    uint32_t newMainBlockAddr = GetLeValue(newSuperBlock->mainBlockId);
    uint32_t offset = oldMainBlockAddr - newMainBlockAddr;
    uint64_t oldEndBlkaddr = (GetLeValue(superBlockData->segmentCountInMain) <<
        GetLeValue(superBlockData->logBlksPerSeg)) + GetLeValue(superBlockData->mainBlockId);
    uint32_t newEndBlkaddr = (GetLeValue(newSuperBlock->segmentCountInMain) <<
        GetLeValue(newSuperBlock->logBlksPerSeg)) + GetLeValue(newSuperBlock->mainBlockId);

    uint64_t tmpEndBlkaddr = newEndBlkaddr + offset;
    ret = resizeDefrag_->HmfsDefragment(tmpEndBlkaddr, oldEndBlkaddr - tmpEndBlkaddr, tmpEndBlkaddr, 1);
    HMFS_INFO("Try to do defragement: %s", ret ? "Insufficient Space" : "Done");
    if (ret != SUCCESS_CODE) {
        return -ENOSPC;
    }
    UpdateSuperBlock(newSuperBlock, SUPER_BLOCK_MASK_ALL);
    RebuildCheckpoint(newSuperBlock, 0);
    return SUCCESS_CODE;
}

int32_t ResizeOperator::HmfsResize()
{
    HMFS_DEBUG("Enter HmfsResize");
    HMFS_CHECK(CreateDeviceInfo() == SUCCESS_CODE, return EXIT_ERR_CODE, "Failed to create device info");
    HMFS_CHECK(InitDeviceInfoToConfig() == SUCCESS_CODE, return EXIT_ERR_CODE, "Failed to init device info config");
    ResizeLoad resizeLoad(config_, superBlockInfo_);
    int32_t ret = resizeLoad.HmfsLoadData();
    if (ret != SUCCESS_CODE) {
        if (ret == CONFIG_LAYOUT) {
            HMFS_INFO("No error was reported");
            return SUCCESS_CODE;
        }
        return ret;
    }
    HMFS_CHECK_ONLY_EXPER(config_->targetSectors != 0, config_->targetSectors = config_->totalSectors);
    if (config_->targetSectors > config_->totalSectors) {
        HMFS_ERROR("Out-of-range Target=0x%" PRIx64 " / 0x%" PRIx64 "", config_->targetSectors, config_->totalSectors);
        return ret;
    }
    return PerformResize();
}

int32_t ResizeOperator::PerformResize()
{
    SuperBlockData *superBlockData = superBlockInfo_->rawSuper;
    uint64_t configBlockCount = (config_->targetSectors * config_->sectorSize) >>
        GetLeValue(superBlockData->logBlockSize);
    uint64_t curBlockCount = GetLeValue(superBlockData->blockCount);

    if (configBlockCount < curBlockCount) {
        if (config_->safeResize == 0) {
            HMFS_ERROR("Nothing to resize, now only supports resizing with safe resize flag\n");
            return SUCCESS_CODE;
        }
        if (HmfsResizeShrink() != SUCCESS_CODE) {
            return SUCCESS_CODE; // consistent with f2fs-tools
        }
    } else if ((configBlockCount > curBlockCount) || (config_->force != 0)) {
        if (HmfsResizeExpand() != SUCCESS_CODE) {
            return SUCCESS_CODE; // consistent with f2fs-tools
        }
    } else {
        HMFS_INFO("Nothing to resize.\n");
        return SUCCESS_CODE;
    }
    return HmfsIo::GetInstance().HmfsFinalizeDevice();
}

int32_t ResizeOperator::CreateDeviceInfo()
{
    for (size_t i = 0; i < resizeConfig_.deviceList.size(); i++) {
        if (DeviceManager::GetInstance().CreateDeviceInfo(resizeConfig_.deviceList[i], i == 0)) {
            return EXIT_ERR_CODE;
        }
    }
    return SUCCESS_CODE;
}

int32_t ResizeOperator::InitDeviceInfoToConfig()
{
    for (uint32_t i = 0; i < resizeConfig_.deviceList.size(); i++) {
        DeviceInfo *deviceInfo = DeviceManager::GetInstance().GetDeviceInfo(i);
        if (deviceInfo == nullptr) {
            HMFS_DEBUG("Failed to get device info");
            continue;
        }
        config_->devices[i].path = deviceInfo->path;
        config_->devices[i].fd = deviceInfo->fd;
        if (i == 0) {
            config_->sectorSize = deviceInfo->sectorSize;
            config_->blockSectorCount = HMFS_BLOCK_SIZE / config_->sectorSize;
        } else {
            if (deviceInfo->sectorSize != config_->sectorSize) {
                HMFS_ERROR("different sector sizes");
                return EXIT_ERR_CODE;
            }
        }
        config_->totalSectors += deviceInfo->sectorCount;
    }
    config_->deviceNumber = DeviceManager::GetInstance().GetDeviceCount();
    if (config_->totalSectors == 0) {
        return EXIT_ERR_CODE;
    }
    return SUCCESS_CODE;
}

ResizeOperator::~ResizeOperator()
{
    NodeAddressTable *nodeAddrTable = superBlockInfo_->nodeAddrTable;
    if (nodeAddrTable != nullptr) {
		HMFS_CHECK_ONLY_EXPER(nodeAddrTable->nodeIdBitmap == nullptr, free(nodeAddrTable->nodeIdBitmap));
        HMFS_CHECK_ONLY_EXPER(nodeAddrTable->natBitmap == nullptr, free(nodeAddrTable->natBitmap));
    }
    HMFS_CHECK_ONLY_EXPER(superBlockInfo_->nodeAddrTable == nullptr, free(superBlockInfo_->nodeAddrTable));
    SegmentInfoTable *segmentTable = superBlockInfo_->segmentTable;
    if (segmentTable != nullptr) {
        SitInfo *sitInfo = superBlockInfo_->segmentTable->sitInfo;
        if(sitInfo != nullptr) {
            HMFS_CHECK_ONLY_EXPER(sitInfo->bitmap == nullptr, free(sitInfo->bitmap));
            HMFS_CHECK_ONLY_EXPER(sitInfo->sitBitmap == nullptr, free(sitInfo->sitBitmap));
            HMFS_CHECK_ONLY_EXPER(sitInfo->segEntries == nullptr, free(sitInfo->segEntries));
        }
        HMFS_CHECK_ONLY_EXPER(segmentTable->sitInfo == nullptr, free(segmentTable->sitInfo));
        if (segmentTable->currentSegmentArray != nullptr) {
            for (uint32_t i = 0; i < CURSEG_TYPE_MAX; i++) {
                HMFS_CHECK_ONLY_EXPER(segmentTable->currentSegmentArray[i].summaryBlockData == nullptr, 
                    free(segmentTable->currentSegmentArray[i].summaryBlockData));
            }
        }
        HMFS_CHECK_ONLY_EXPER(segmentTable->currentSegmentArray == nullptr, free(segmentTable->currentSegmentArray));
    }
    HMFS_CHECK_ONLY_EXPER(superBlockInfo_->segmentTable == nullptr, free(superBlockInfo_->segmentTable));
    HMFS_CHECK_ONLY_EXPER(superBlockInfo_->checkPointData == nullptr, free(superBlockInfo_->checkPointData));
    HMFS_CHECK_ONLY_EXPER(superBlockInfo_->rawSuper == nullptr, free(superBlockInfo_->rawSuper));
}
}
}
